package io.github.talelin.latticy.common.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.talelin.latticy.common.exception.ServerErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;


/**
 * Json和实体的转换工具类
 *
 * @author YiHua
 * @date 2021/9/1 11:48 下午
 */
@Component
public class GenericAndJson {

    // 序列化使用的工具是：jackson

    // FIXME 笔记：注入之后要在静态方法中使用的注入方式，也可以理解为静态注入的方式
    private static ObjectMapper mapper;

    @Autowired
    public void setMapper(ObjectMapper mapper) {
        GenericAndJson.mapper = mapper;
    }

    /**
     * 序列化: 将 model >>>> json。
     *
     * @param o   传入的对象
     * @param <T> 转换的json字符串
     */
    public static <T> String objectToJson(T o) {
        try {
            return GenericAndJson.mapper.writeValueAsString(o);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServerErrorException(9999);
        }
    }

    /**
     * 单体的反序列化: json >>>> model
     *
     * @param jsonData json数据
     * @param beanType 对象中的object类型
     * @return T 返回的模型对象
     */
    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
        if (jsonData == null) {
            return null;
        }
        try {
            return mapper.readValue(jsonData, beanType);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /*
     * 问题：多体的反序列化问题，例如: Json ——> List<Object>
     * 1. List<T>  整体看成一个泛型
     * 2. List<T>  只把List里面的内容看成泛型的
     *
     * 注意：多体的反序列化，方法名称：jsonToList，jsonToObject 都行哈
     * 这个和sku的get和set方法关系密切，查看笔记的时候，去看
     */

    /**
     * 多体的反序列化: json >>>> List<object>
     * 解决问题的方式：List<T>  只把List里面的内容看成泛型的
     *
     * @param jsonData json数据对象
     * @param beanType object
     * @param <T>      list<object>
     */
    public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
        if (jsonData == null) {
            return null;
        }
        JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, beanType);
        try {
            return mapper.readValue(jsonData, javaType);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 多体的反序列化: json >>>> List<object>
     * 首先：这个方法单体的/多体的都可以使用，因为你构造 TypeReference的时候传入List/Pojo来决定
     * 解决问题方式：List<T> 这个是把整体看成一个泛型
     * 如何使用：需要构造 ——> TypeReference
     * 例如：GenericAndJson.jsonToObject(this.specs, new TypeReference<List<Spec>>(){});
     *
     * @param jsonData json数据对象
     * @param tr       tr包装的集合对象
     * @param <T>      List<object>
     */
    public static <T> T jsonToListOne(String jsonData, TypeReference<T> tr) {
        if (jsonData == null) {
            return null;
        }
        try {
            return GenericAndJson.mapper.readValue(jsonData, tr);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new ServerErrorException(9999);
        }
    }

    // 下面的方法不行的原因：不传入'TypeReference' 还是没法推断出我们想要的类型如spec，系统会自动给一个hashMap，所以还是失败的

    /**
     * 多体的反序列化: json >>>> List<object>
     * 解决问题的方式：List<T>  只把List里面的内容看成泛型的
     *
     * @param jsonData json数据对象
     * @param <T>      集合中的object
     */
    public static <T> List<T> jsonToListTwo(String jsonData) {
        if (jsonData == null) {
            return null;
        }
        try {
            return GenericAndJson.mapper.readValue(jsonData, new TypeReference<List<T>>() {
            });
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new ServerErrorException(9999);
        }
    }
}